home *** CD-ROM | disk | FTP | other *** search
/ Sound Fx / Sound Fx.iso / Software / UNZIPED / DWSTK / DWDSP.C next >
Encoding:
C/C++ Source or Header  |  1996-10-10  |  9.8 KB  |  392 lines

  1. /*****************************************************************************
  2. File:          dwdsp.c
  3. Version:     2.22
  4. Tab stops: every 2 columns
  5. Project:     DiamondWare's DSP add-on for its STK product
  6. Copyright: 1995 DiamondWare, Ltd.  All rights reserved.
  7. Written:     by Keith Weiner & Erik Lorenzen
  8. Purpose:     Contains DSP functions which operate on DWD buffers
  9. History:     95/03/25 KW Started
  10.                      95/09/29 EL Re-do for speed & clean up
  11.                      95/10/05 KW Finalized for 2.10
  12.                      95/10/18 EL added #if's to get rid of dword indexing warnings in
  13.                                              real mode
  14.                      95/10/20 EL Finalized for 2.20
  15.                      95/11/16 EL Fixed minor bug in volume scaling, maxsample calculation
  16.                                              and enabled dword addressing in p-mode
  17.                      95/12/07 EL Finalized for 2.21, moved typedef's into .c file
  18.                                              they were not needed in the .h
  19.                      96/10/10 EL Finalized for 2.22, no changes
  20. *****************************************************************************/
  21.  
  22.  
  23.  
  24. #include <time.h>
  25.  
  26. #include "dwdsp.h"
  27.  
  28.  
  29.  
  30. #ifndef NULL
  31.     #define NULL ((void *)0)
  32. #endif
  33.  
  34.  
  35. #define TITLELEN    23
  36.  
  37.  
  38. #define TABLESIZE 0x100                                          //number of entries in volume table
  39.  
  40. #define HALFTABLE (TABLESIZE >> 1)
  41.  
  42.  
  43. /*
  44.  . The following types are used by DWDSP
  45.  .
  46.  . If you get a
  47.  .     "Warning! W108: Duplicate typedef already defined"
  48.  . or
  49.  .     "warning C4001: nonstandard extension 'benign typdef redefinition'"
  50.  . (or similar message) no action is needed.
  51.  .
  52.  . If you get a "Error! E1034: Symbol 'xxxxxx' already defined"
  53.  . (or similar message) comment the offending typedef out, or #define
  54.  . stddef_INCLUDE before #including this file.
  55. */
  56. #ifndef stddef_INCLUDE
  57.     typedef char    int8;
  58.     typedef short int16;
  59.     typedef long    int32;
  60. #endif
  61.  
  62.  
  63. /*
  64.  . Absolute maximum volumes for 8-bit sound
  65.  .
  66.  . NB: 0x7f is the max positive value, and 0x80 is the maximum negative.
  67.  .         For further explanation, see any CS text on two's complement.
  68. */
  69. #define MAXPOSVOL  0x7f
  70. #define MAXNEGVOL -0x80
  71.  
  72.  
  73. /*
  74.  . The following two macros are quite useful, aside from their use in
  75.  . DW's DSP.  They are lifted from DW's stddef.h include file.
  76. */
  77. #define dwdsp_ABS(number) (((number) >= 0) ? (number) : -(number))
  78.  
  79. #define dwdsp_SWAP(x,y) {(x) ^= (y); (y) ^= (x); (x) ^= (y);}
  80.  
  81.  
  82. /*
  83.  . NB: In order to use this struct it must be packed, otherwise the
  84.  .         code that uses it will get false info and crash the machine.
  85. */
  86. #ifdef _MSC_VER
  87.     #pragma pack(1)             /*Microsoft byte align*/
  88. #endif
  89.  
  90. #ifdef __WATCOMC__
  91.     #pragma pack(1)             /*Watcom byte align*/ //NB: compatible w/Microsoft!
  92. #endif
  93.  
  94. #ifdef __BORLANDC__
  95.     #pragma option -a-        /*Borland byte align*/ //NB: product differentiation!
  96. #endif
  97.  
  98.  
  99.  
  100. typedef struct
  101. {
  102.     char    title[23];            /*DiamondWare Digitized\n\0                                              */
  103.     byte    eof;                        /*1A (EOF to abort printing of file)                             */
  104.     byte    majorver;             /*Major Version number                                                         */
  105.     byte    minorver;             /*Minor                 "       "                                                  */
  106.     dword id;                         /*Unique sound ID                                                                  */
  107.     byte    reserved1;            /*Oops! :)                                                                                 */
  108.     byte    compress;             /*Compression type (0=none)                                              */
  109.     word    rate;                     /*Sampling Rate (in Hz)                                                      */
  110.     byte    channels;             /*(1=mono, 2=stereo)                                                             */
  111.     byte    bits;                     /*Bits per sample per channel 8,16)                              */
  112.     word    maxsample;            /*dwdsp_ABSolute value of largest sample in file     */
  113.     dword length;                 /*Length of data section (in bytes)                              */
  114.     dword numsmp;                 /*Num samples (16bit stereo would be 4bytes/sample)*/
  115.     dword offset;                 /*Offset of data file from start of file (in bytes)*/
  116.  
  117. } HDR;
  118.  
  119.  
  120.  
  121. #ifdef _MSC_VER
  122.     #pragma pack()                /*Microsoft reset pack option to default cmdln*/
  123. #endif
  124.  
  125. #ifdef __BORLANDC__
  126.     #pragma option -a.        /*Borland reset pack option to default or cmdln*/
  127. #endif
  128.  
  129. #ifdef __WATCOMC__
  130.     #pragma pack()                /*Watcom reset pack option to default cmdln*/
  131. #endif
  132.  
  133.  
  134.  
  135. typedef union
  136. {
  137.     HDR  hdr;
  138.     byte data[1];                                                          //we don't really use a len of 1
  139.  
  140. } DWD;
  141.  
  142.  
  143. static word errnum=dwdsp_EZERO;                          //initialize errnum
  144.  
  145. static byte dwdtitle[TITLELEN] = "DiamondWare Digitized\n";
  146.  
  147.  
  148.  
  149. /****************************************************************************
  150. * Private functions
  151. ****************************************************************************/
  152. static word CheckDWDHdr(byte *srcdwd)
  153. {
  154.     word x;
  155.  
  156.     for (x=0;x<TITLELEN;x++)
  157.     {
  158.         if (srcdwd[x] != dwdtitle[x])
  159.         {
  160.             return (0);
  161.         }
  162.     }
  163.  
  164.     return (1);
  165. }
  166.  
  167.  
  168. static void CopyDWDHdr(byte *srcdwd, byte *desdwd)
  169. {
  170.     DWD *ds=(DWD *)srcdwd;
  171.     DWD *dd=(DWD *)desdwd;
  172.     time_t timer;
  173.     word x;
  174.  
  175.     for (x=0;x<ds->hdr.offset;x++)                         //ds->hdr.offset is the begining
  176.     {                                                                                  //of the data section of the DWD,
  177.         dd->data[x] = ds->data[x];                             //everything before that can be
  178.     }                                                                                  //considerd header
  179.  
  180.     time(&timer);                                                          //xor with time to give it a new
  181.     dd->hdr.id ^= timer;                                             //unique (enough) id
  182. }
  183.  
  184.  
  185. static dword GCF(dword a, dword b)                     //Greatest Common Factor
  186. {
  187.     if (b > a)
  188.     {
  189.         dwdsp_SWAP(a, b);
  190.     }
  191.  
  192.     if (!b)
  193.     {
  194.         return (a);
  195.     }
  196.     else
  197.     {
  198.         return (GCF(b, a % b));
  199.     }
  200. }
  201.  
  202.  
  203. static dword LCM(dword a, dword b)                     //Least Common Multiple
  204. {
  205.     return ((a * b) / GCF(a, b));
  206. }
  207.  
  208.  
  209. /****************************************************************************
  210. * Public functions
  211. ****************************************************************************/
  212. word dwdsp_ErrNo (void)
  213. {
  214.     return (errnum);
  215. }
  216.  
  217.  
  218. word dwdsp_ChngLen(byte *desdwd, byte *srcdwd, dword newlen)
  219. {
  220.     DWD *ds=(DWD *)srcdwd;
  221.     DWD *dd=(DWD *)desdwd;
  222.     int8 *srcdata;
  223.     int8 *desdata;
  224.     double tmp;
  225.     dword  srclen;
  226.     dword  deslen;
  227.     dword  hdrsize;
  228.     dword  interpidx;
  229.     dword  interpsmp;
  230.     dword  lcm;
  231.     dword  x;
  232.  
  233.     if ((srcdwd == NULL) || (desdwd == NULL))
  234.     {
  235.         errnum = dwdsp_NULLPTR;                                  //sorry can't use a NULL ptr
  236.         return (0);
  237.     }
  238.  
  239.     if (!CheckDWDHdr(srcdwd))
  240.     {
  241.         errnum = dwdsp_NOTADWD;                                  //sorry can't use srcdwd that
  242.         return (0);                                                          //doesn't pt to a DWD
  243.     }
  244.  
  245.     if (srcdwd == desdwd)
  246.     {
  247.         errnum = dwdsp_SAMEPTR;                                  //sorry can't do this operation
  248.         return (0);                                                          //on the source buffer
  249.     }
  250.  
  251.     hdrsize = ds->hdr.offset;
  252.  
  253.     if (newlen <= hdrsize)
  254.     {
  255.         errnum = dwdsp_BADLEN;                                     //the result DWD is too short
  256.         return (0);                                                          //to have any data!
  257.     }
  258.  
  259.     CopyDWDHdr(srcdwd, desdwd);                              //make sure hdr is up to date
  260.  
  261.     #ifdef __FLAT__                                                      //make sure not to index by a
  262.                                                                                          //dword unless flat model is used
  263.         srcdata = (int8 *)(ds->data + hdrsize);  //point to the begining of data
  264.         desdata = (int8 *)(dd->data + hdrsize);  //in the DWDs
  265.     #else
  266.         srcdata = (int8 *)(ds->data + (word)hdrsize); //point to the begining of data
  267.         desdata = (int8 *)(dd->data + (word)hdrsize); //in the DWDs
  268.     #endif
  269.  
  270.     srclen = ds->hdr.length;
  271.     deslen = newlen - hdrsize;
  272.  
  273.     lcm = LCM(srclen, deslen);
  274.  
  275.     dd->hdr.length = deslen;                                     //set destination DWD data length
  276.  
  277.     /*
  278.      . Go through source DWD, and either duplicate or remove samples
  279.      . in order to "pitch shift" a sound.  It's not as mathematically
  280.      . correct as the real technique, but it's much faster.
  281.      .
  282.      . NB: The use of floating-point operations has more to do with
  283.      .         readability than performance, except on Pentium(R) processors! :)
  284.      .         (serious) A technique akin to Bresenham's line would quickly
  285.      .         convert this to integer-math.
  286.     */
  287.     for (x=0;x<deslen;x++)
  288.     {
  289.         tmp = ((double)x * (double)lcm) / (double)deslen;
  290.         interpidx = (dword)tmp;
  291.  
  292.         tmp = ((double)interpidx * (double)srclen) / (double)lcm;
  293.         interpsmp = (dword)tmp;
  294.  
  295.         #ifdef __FLAT__                                                  //make sure not to index by a
  296.                                                                                          //dword unless flat model is used
  297.             desdata[x] = srcdata[interpsmp];
  298.         #else
  299.             desdata[(word)x] = srcdata[(word)interpsmp];
  300.         #endif
  301.     }
  302.  
  303.     return (1);
  304. }
  305.  
  306.  
  307. word dwdsp_ChngVol(byte *desdwd, byte *srcdwd, word vollev)
  308. {
  309.     DWD *ds=(DWD *)srcdwd;
  310.     DWD *dd=(DWD *)desdwd;
  311.     dword min=ds->hdr.offset;
  312.     dword max=ds->hdr.length+ds->hdr.offset;
  313.     static byte table[TABLESIZE];                          //don't put it on the stack
  314.     word    loop;
  315.     word    tblidx;                                                          //used to index into mixing table
  316.     int32 tmp;
  317.     int32 volume;
  318.     dword buffidx;                                                         //used to index into DWD buffers
  319.  
  320.     if ((srcdwd == NULL) || (desdwd == NULL))
  321.     {
  322.         errnum = dwdsp_NULLPTR;
  323.         return(0);
  324.     }
  325.  
  326.     if (!CheckDWDHdr(srcdwd))
  327.     {
  328.         errnum = dwdsp_NOTADWD;
  329.         return(0);
  330.     }
  331.  
  332.     if (srcdwd != desdwd)                                          //if the source is different from
  333.     {                                                                                  //the destination copy the header
  334.         CopyDWDHdr(srcdwd, desdwd);
  335.     }
  336.  
  337.     for (loop=0;loop<HALFTABLE;loop++)
  338.     {
  339.         /* Postive numbers */
  340.         volume = (int32)loop;
  341.         tblidx = loop;
  342.  
  343.         tmp = ((volume * (int32)vollev) / dwdsp_IDENTITY);
  344.  
  345.         if (tmp > MAXPOSVOL)
  346.         {
  347.             tmp = MAXPOSVOL;                                             //clip if it exceeds the
  348.         }                                                                              //dynamic range
  349.  
  350.         table[tblidx] = (byte)tmp;
  351.  
  352.         /* Negative numbers */
  353.         volume = MAXNEGVOL + (int32)loop;
  354.         tblidx = (word)(HALFTABLE + loop);
  355.  
  356.         tmp = ((volume * (int32)vollev) / dwdsp_IDENTITY);
  357.  
  358.         if (tmp < MAXNEGVOL)
  359.         {
  360.             tmp = MAXNEGVOL;                                             //clip if it exceeds the
  361.         }                                                                              //dynamic range
  362.  
  363.         table[tblidx] = (byte)tmp;
  364.     }
  365.  
  366.     for (buffidx=min;buffidx<max;buffidx++)      //convert sound
  367.     {
  368.         #ifdef __FLAT__                                                  //make sure not to index by a
  369.                                                                                          //dword unless flat model is used
  370.             dd->data[buffidx] = table[ds->data[buffidx]];
  371.         #else
  372.             dd->data[(word)buffidx] = table[ds->data[(word)buffidx]];
  373.         #endif
  374.     }
  375.  
  376.  
  377.     /*
  378.      . Set dd->hdr.maxsample.
  379.      .
  380.      . NB: dd->hdr.maxsample is always a positive number.
  381.     */
  382.  
  383.     dd->hdr.maxsample = (word)((ds->hdr.maxsample * vollev) / dwdsp_IDENTITY);
  384.  
  385.     if (dd->hdr.maxsample > MAXPOSVOL)
  386.     {
  387.         dd->hdr.maxsample = MAXPOSVOL;
  388.     }
  389.  
  390.     return (1);
  391. }
  392.